<?php
	/**
	  * @package	MySQLWrapper
	  * @name		MySQLAssistant
	  * @brief		Clase para armar consultas y ejecutarlas en un servidor MySQL
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://opensource.org/licenses/gpl-2.0.php
	  * @date		2010-01-04
	  * @version	0.1.1
  	**/

	final class MySQLAssistant extends MySQLProcess implements SQLAll, MyVersions {
		/* version de la clase */
		private static $version			= 0;
		/* subversion de la clase */
		private static $subversion		= 1;
		/* numero de revision de la clase */
		private static $revision		= 1;

		/* estado de la transaccion */
		private $transaccion = False;

		public function __construct($debug = False) {
			/* enviamos el constructor del padre */
			parent::__construct($debug, __CLASS__);
		}

		public function __destruct() {
			/* enviamos el destructor padre */
			parent::__destruct();
		}

		public static function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		public function setWhere($where = Null) {
			try {
				try {
					/* mostramos un mensaje */
					$this->show('Asignando filtro WHERE..', False);
					/* verificamos que los parametros sean correctos y agregamos el WHERE a la consulta */
					$this->armarWhere($where, $this->validarWhere($where));
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* comstramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function setOrderBy($order = Null, $asc = True) {
			try {
				try {
					/* mostramos un mensaje */
					$this->show('Asignando clausula ORDER BY..', False);
					/* verificamos los datos */
					$this->validarOrderBy($order, $asc);
					/* armamos el ORDER para la consulta */
					$this->armarOrderBy($order, $asc);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* comstramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function setLimit($limit = Null, $cantidad = Null) {
			try {
				try {
					/* mostramos un mensaje para identificar que estamos haciendo */
					$this->show('Asignando clausula LIMIT..', False);
					/* validamos los datos */
					$this->validarLimit($limit, $cantidad);
					/* armamos el LIMIT */
					$this->armarLimit($limit, $cantidad);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function selectFrom($campos = Null, $tabla = Null, $showMy = True) {
			try {
				try {
					/* verificamos si utilizamos internamente */
					if ($showMy)
						/* mostramos un mensaje  */
						$this->show('Armando consulta SELECT..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos que se envio un nombre de tabla */
					if ($this->validarSelectFrom($campos, $tabla) === True) {
						/* invertimos ya que se especifico solo el nombre de la tabla */
						$tabla = $campos;
						/* vaciamos los campos */
						$campos = Null;
					}
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos el SELECT */
					$this->armarSelectFrom($campos, $tabla, $showMy);
					/* verificamos si utilizamos internamente */
					if ($showMy) {
						/* mostramos la consulta */
						$this->showSQL();
						/* mostramos el OK al mensaje */
						$this->showOK();
					}
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* verificamos si utilizamos internamente */
				if ($showMy)
					/* mostramos el mensaje */
					$this->show($e->getMensaje());
				else
					/* sino, produzco uno para que salte al try catch del metodo que me llamo */
					$this->newException($e);
			}
		}

		public function selectFromJoin($campos = Null, $deTabla = Null, $tablas = Null) {
			try {
				try {
					/* mostramos un mensaje */
					$this->show('Armando consulta SELECT con JOIN..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos los datos recibidos */
					$this->verificarSelectFromJoin($campos, $deTabla, $tablas);
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos la consulta con JOIN */
					$this->armarSelectFromJoin($campos, $deTabla, $tablas);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function insertInto($tabla = Null, $datos = Null) {
			try {
				try {
					/* mostramos un mensaje para identificar que hacemos */
					$this->show('Armando consulta INSERT INTO..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos los valores recibidos */
					$this->validarInsert($tabla, $datos);
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* comenzamos a armar la consulta SQL */
					$this->armarInsert($tabla, $datos);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function insertIntoFields($tabla = Null, $datos = Null) {
			try {
				try {
					/* mostramos un mensaje */
					$this->show('Armando consulta INSERT INTO con especificacion de campos..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos los valores recibidos */
					$this->validarInsert($tabla, $datos, True);
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* comenzamos a armar la consulta SQL */
					$this->armarInsertFields($tabla, $datos);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function updateSet($tabla = Null, $campos = Null) {
			try {
				try {
					/* mostramos un mensaje */
					$this->show('Armando consulta UPDATE..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos los valores recibidos */
					$this->validarUpdate($tabla, $campos);
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos la consulta SQL */
					$this->armarUpdate($tabla, $campos);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function deleteFrom($tabla = Null) {
			try {
				try {
					/* mostramos un mensaje para identificar que hacemos */
					$this->show('Armando consulta DELETE FROM..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos los valores recibidos */
					$this->validarDeleteFrom($tabla);
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos la consulta sql */
					$this->armarDeleteFrom($tabla);
					/* mostramos la consulta */
					$this->showSQL();
					/* mostramos el OK al mensaje */
					$this->showOK();
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function iniciarTransaccion() {
			try {
				try {
					/* mostramos un mensaje para identificar que hacemos */
					$this->show('Iniciando transaccion ' . $this->yellow('(Obs: El motor de Base de Datos debe soportar transacciones)') . '..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos si ya no hay una transaccion en proceso */
					if ($this->transaccion)
						/* salimos con una excepcion */
						$this->newException('Ya existe una transaccion en progreso');
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos el SQL */
					$this->addSQL("SET AUTOCOMMIT=0", True);
					/* mostramos el OK al mensaje */
					$this->showOK();
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* armamos el SQL */
					$this->addSQL("START TRANSACTION", True);
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* almacenamos el estado de la transaccion */
					$this->transaccion = True;
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function finalizarTransaccion() {
			try {
				try {
					/* mostramos un mensaje para identificar que hacemos */
					$this->show('Finalizando transaccion..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos si ya no hay una transaccion en proceso */
					if ($this->transaccion === False)
						/* salimos con una excepcion */
						$this->newException('No existe ninguna transaccion en progreso');
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos el SQL */
					$this->addSQL('COMMIT', True);
					/* mostramos el OK al mensaje */
					$this->showOK();
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* armamos el SQL */
					$this->addSQL('SET AUTOCOMMIT=1', True);
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* finalizamos la transaccion */
					$this->transaccion = False;
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		public function cancelarTransaccion() {
			try {
				try {
					/* mostramos un mensaje para identificar que hacemos */
					$this->show('Cancelando transaccion..', False);
					/* verificamos si existe una conexion */
					$this->verificarConexion();
					/* verificamos si ya no hay una transaccion en proceso */
					if ($this->transaccion === False)
						/* salimos con una excepcion */
						$this->newException('No existe ninguna transaccion en progreso');
					/* buscamos por un SQL sin ejecutar */
					$this->consultaSinEjecutar(True);
					/* armamos el SQL */
					$this->addSQL('ROLLBACK', True);
					/* mostramos el OK al mensaje */
					$this->showOK();
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* armamos el SQL */
					$this->addSQL('SET AUTOCOMMIT=1', True);
					/* ejecutamos la consulta */
					$this->ejecutarSQL();
					/* finalizamos la transaccion */
					$this->transaccion = False;
				} catch (Exception $e) {
					/* convertimos la excepcion a mi excepcion */
					$this->newException($e);
				}
			} catch (MyException $e) {
				/* mostramos el mensaje */
				$this->show($e->getMensaje());
			}
		}

		private function validarWhere($where) {
			/* creamos una variable temporal */
			$toAdd = ' WHERE ';
			/* verificamos si se especifico la cadena where */
			if ($where === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico clausula WHERE');
			/* verificamos que el parametro sea un string */
			if (gettype($where) !== 'string')
				/* salimos con una excepcion */
				$this->newException('La clausula WHERE debe ser un string');
			/* verificamos si existe una consulta para agregar WHERE */
			if ($this->existeSQL() === False)
				/* salimos con una excepcion */
				$this->newException('No existe una consulta para agregar la clausula WHERE');
			/* verificamos que la consulta no sea un INSERT */
			if (preg_match('/insert/i', $this->getSqlString()))
				/* salimos con una excepcion */
				$this->newException('No se puede agregar un filtro WHERE en una consulta INSERT');
			/* verificamos que no exista un LIMIT */
			if (preg_match('/limit/i', $this->getSqlString()))
				/* salimos con una excepcion */
				$this->newException('No se puede agregar un filtro WHERE luego de la existencia de un LIMIT');
			/* verificamos que no exista un ORDER BY */
			if (preg_match('/order by/i', $this->getSqlString()))
				/* salimos con una excepcion */
				$this->newException('No se puede agregar un filtro WHERE luego de la existencia de un ORDER BY');
			/* verificamos si ya tiene una clausula WHERE */
			if (preg_match('/where/i', $this->getSqlString()))
				/* modificamos el valor por AND */
				$toAdd = ' AND ';
			/* retornamos la cadena */
			return $toAdd;
		}

		private function armarWhere($where, $toAdd) {
			/* agregamos el WHERE a la consulta */
			$this->addSQL(
				/* buscamos por otro WHERE en la cadena */
				strtolower(substr($this->getSqlString(), -5)) == 'where' ?
				/* si ya existe un WHERE agregamos un espacio */
				' ' . (
					/* si la cadena enviada tiene un WHERE */
					strtolower(substr($where, 0, 5)) == 'where' ?
					/* se lo eliminamos */
					substr($where, 5) :
					/* sino, agregamos la cadena como esta */
					$where
				/* si no tiene un WHERE */
				) : (
					/* verificamos si la cadena enviada tiene un WHERE */
					strtolower(substr($where, 0, 5)) == 'where' ?
					/* si ya tiene agregamos con el WHERE de la cadena original */
					$where :
					/* sino, agregamos la cadena como esta seguida del WHERE */
					$toAdd . $where
				)
			);
		}

		private function validarOrderBy($order, $asc) {
			/* verificamos si se especifico el parametro ORDER BY */
			if ($order === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico el campo para asignar el orden');
			/* verificamos si existe una consulta para agregar WHERE */
			if ($this->existeSQL() === False)
				/* salimos con una excepcion */
				$this->newException('No existe una consulta para agregar la clausula ORDER BY');
			/* verificamos que envio correctamente el parametro ORDER BY */
			if (gettype($order) !== 'array')
				/* salimos con una excepcion */
				$this->newException('El valor para ORDER BY debe ser enviado por medio de un Array');
			/* verificamos que envio correctamente el parametro ASC */
			if (gettype($asc) !== 'boolean')
				/* salimos con una excepcion */
				$this->newException('El valor de orden debe ser especificado por medio de un valor booleano');
			/* verificamos si la cadena SQL ya tiene una clausula LIMIT */
			if (preg_match('/limit/i', $this->getSqlString()))
				/* salimos con una excepcion */
				$this->newException('No se puede agregar una clausula ORDER BY luego de la existencia de una clausula LIMIT');
		}

		private function armarOrderBy($order, $asc) {
			/* agregamos la clausula ORDER BY */
			$this->addSQL(
				/* varificamos si ya tiene un ORDER BY */
				preg_match('/order by/i', $this->getSqlString()) ?
				/* agregamos una separacion */
				', ' :
				/* agregamos la clausula ORDER BY */
				' ORDER BY '
			);
			/* recorremos los campos */
			foreach ($order AS $campo)
				/* agregamos el campo */
				$this->addSQL($campo . ', ');
			/* eliminamos la coma y espacio restantes */
			$this->cleanSQL();
			/* agregamos el sentido de orden */
			$this->addSQL(' ' . (
				/* verificamos si es ascendente */
				$asc === True ?
				/* agregamos ASC */
				'ASC' :
				/* agregamos DESC */
				'DESC'
			));
		}

		private function validarLimit($limit, $cantidad) {
			/* verificamos si envio un parametro LIMIT */
			if ($limit === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico la cantidad para LIMIT');
			/* verificamos que el valor sea entero */
			if (gettype($limit) !== 'integer')
				/* salimos con una excepcion */
				$this->newException('El valor para LIMIT debe ser entero');
			/* verificamos que no se alla enviado un valor negativo */
			if ($limit < 0 || ($cantidad !== Null && $cantidad < 0))
				/* salimos con una excepcion */
				$this->newException('El valor para LIMIT debe ser mayor a cero');
			/* verificamos si existe una consulta para agregar LIMIT */
			if ($this->existeSQL() === False)
				/* salimos con una excepcion */
				$this->newException('No existe una consulta para agregar la clausula LIMIT');
			/* verificamos que no tenga ya un limite */
			if (preg_match('/limit/i', $this->getSqlString()))
				/* salimos con una excepcion */
				$this->newException('La consulta actual ya posee un valor para LIMIT');
		}

		private function armarLimit($limit, $cantidad) {
			/* agregamos la clausula LIMIT a la consulta */
			$this->addSQL(' LIMIT ' . $limit);
			/* verificamos si envio cantidad */
			if ($cantidad !== Null)
				/* la agregamos a la consulta */
				$this->addSQL(', ' . $cantidad);
		}

		private function validarSelectFrom($campos, $tabla) {
			/* verificamos si solo se envio el nombre de la tabla */
			if ($tabla === Null && gettype($campos) == 'string')
				/* retornamos true */
				return True;
			else
				/* verificamos el nombre de la tabla */
				$this->validarNombre($tabla);
			/* retornamos false */
			return False;
		}

		private function validarNombre($tabla) {
			/* verificamos que se envio un nombre de tabla */
			if ($tabla === Null)
				/* salimos con una excepcion */
				$this->newException('No se especifico el nombre de la tabla');
			/* verificamos si se especifico un string */
			if (gettype($tabla) != 'string')
				/* salimos con una excepcion */
				$this->newException('El nombre de la tabla debe ser un string');
		}

		private function armarSelectFrom($campos, $tabla, $showMy) {
			/* verificamos si envio campos para seleccionar */
			if ($campos === Null && $showMy) {
				/* mostramos un mensaje */
				$this->show('No se especifico los campos a seleccionar, se asume \'*\'..', False);
				/* modificamos el valor de los campos */
				$campos = '*';
			/* verificamos que los campos se enviaron como array */
			} elseif (gettype($campos) != 'array')
				/* salimos con una excepcion */
				$this->newException('El nombre de los campos a seleccionar deben ser pasados como Array');
			else {
				/* creamos una variable temporal donde almacenaremos la cadena del SELECT */
				$temp = '';
				/* recorremos todos los campos enviados como parametros */
				foreach ($campos AS $tits => $item)
					/* agregamos a la cadena temporal el campo actual */
					$temp .= (
						/* si el indice del array es string */
						gettype($tits) === 'string' ?
						/* el SELECT tendra ese campo de la siguiente manera: ..., campo1 AS nombreDeseado */
						$tits . ' AS ' . $item :
						/* sino agregamos el campo simplemente */
						$item
					/* agregamos la coma para separar los campos */
					) . ', ';
				/* eliminamos la coma y el espacio sobrante */
				$campos = substr($temp, 0, -2);
			}
			/* armamos la cabecera del SELECT */
			$this->addSQL('SELECT ' . $campos . ' FROM ' . $tabla, True);
			/* limpiamos la cadena SQL */
			$this->cleanSQL();
		}

		private function verificarSelectFromJoin($campos, $deTabla, $tablas) {
			/* verificamos si especifico los campos */
			if ($campos === Null)
				/* salimos con una excpecion */
				$this->newException('No se especificaron los campos a seleccionar');
			/* verificamos que los campos se especificaron en un array */
			if (gettype($campos) !== 'array')
				/* salimos con una excpecion */
				$this->newException('Los campos deben ser especificados mediante un array');
			/* verificamos si especifico la tabla central */
			if ($deTabla === Null)
				/* salimos con una excpecion */
				$this->newException('No se especifico la tabla central');
			/* verificamos que la tabla principal se especifico en un string */
			if (gettype($deTabla) !== 'string')
				/* salimos con una excpecion */
				$this->newException('La tabla central debe ser especificada mediante un string');
			/* verificamos si especifico la tabla central */
			if ($tablas === Null)
				/* salimos con una excpecion */
				$this->newException('No se especificaron las tablas del JOIN');
			/* verificamos si se envio correctamente los JOIN */
			foreach ($tablas AS $tabla => $on) {
				/* si el indice ($tabla) no es un string esta incorrecto */
				if (gettype($tabla) !== 'string')
					/* salimos con una excepcion */
					$this->newException('Las tablas para el JOIN no se enviaron correctamente');
			}
		}

		private function armarSelectFromJoin($campos, $deTabla, $tablas) {
			/* creamos un array temporal donde armaremos los campos */
			$arrayCampos = Array();
			/* recorremos los campos */
			foreach ($campos AS $campo => $valor)
				/* agregamos el campo */
				$arrayCampos[] = (
					/* si el indice del array es string */
					gettype($campo) === 'string' ?
					/* el SELECT tendra ese campo de la siguiente manera tbl1.campo1, tbl2.campo2, tbl2.campo3 */
					$campo . '.' . $valor :
					/* sino agregamos el campo como tabla y un asterisco, tbl1.* */
					$valor . '.*'
				);
			/* armamos los JOIN */
			$join = $deTabla . ' JOIN ';
			/* recorremos las tablas */
			foreach ($tablas AS $tabla => $on)
				/* agregamos el JOIN */
				$join .= $tabla . ' ON ' . $on . ' JOIN ';
			/* eliminamos el ultimo JOIN de mas */
			$join = substr($join, 0, -5);
			/* llamamos al metodo selectFrom con los parametros modificados */
			$this->selectFrom($arrayCampos, $join, False);
		}

		private function validarInsert($tabla, $datos, $indices = False) {
			/* verificamos que se envio un nombre de tabla */
			$this->validarNombre($tabla);
			/* verificamos los datos */
			if ($datos === Null)
				/* mostramos un mensaje de error */
				$this->newException('No se especificaron los datos a almacenar');
			/* verificamos que los campos se especificaron en un array */
			if (gettype($datos) !== 'array')
				/* mostramos un mensaje de error */
				$this->newException('Los datos a almacenar deben ser especificados en un Array');
			/* verificamos si se especifico los indices */
			if ($indices) {
				/* recorremos los datos para verificar en indice */
				foreach ($datos AS $indice => $valor) {
					/* verificamos si el indice es un string */
					if (gettype($indice) !== 'string')
						/* salimos con una excepcion */
						$this->newException('El indice de los datos deben ser pasados como String');
				}
			}
		}

		private function armarInsert($tabla, $datos) {
			/* creamos el inicio de la consulta el inicio de la consulta */
			$this->addSQL('INSERT INTO ' . $tabla . ' VALUES (', True);
			/* recorremos los campos */
			foreach ($datos AS $valor)
				/* agregamos el campo */
				$this->addSQL(
					/* verificamos si es un integer */
					gettype($valor) == 'integer' ?
					/* agregamos el valor sin comillas */
					$valor . ', ' : (
						/* verificamos si es Null */
						$valor === Null ?
						/* agregamos el texto Null */
						'Null, ' :
						/* agregamos con las comillas */
						'\'' . addslashes($valor) . '\', '
					)
				);
			/* limpiamos el SQL */
			$this->cleanSQL();
			/* finalizamos el INSERT */
			$this->addSQL(')');
		}

		private function armarInsertFields($tabla, $datos) {
			/* creamos una variable temporal donde almacenaremos los campos */
			$fields = Null;
			/* creamos una variable temporal donde almacenaremos los valores de los campos */
			$values = Null;
			/* asignamos el inicio de la consulta */
			$this->addSQL('INSERT INTO ' . $tabla, True);
			/* recorremos los campos */
			foreach ($datos AS $campo => $valor) {
				/* agregamos el nombre del campo */
				$fields .= $campo . ', ';
				/* agregamos el valor del campo */
				$values .= (
					/* verificamos si es entero */
					gettype($valor) == 'integer' ?
					/* lo agregamos sin las comillas */
					$valor . ', ' : (
						/* verificamos si es null */
						$valor === Null ?
						/* agregamos el texto Null */
						'Null, ' :
						/* agregamos el valor entre comillas */
						'\'' . addslashes($valor) . '\', '
					)
				);
			}
			/* eliminamos la coma y espacio sobrante de los campos */
			$fields = substr($fields, 0, -2);
			/* eliminamos la coma y espacio sobrante de los valores */
			$values = substr($values, 0, -2);
			/* le agregamos a la cadena INSERT los campos y sus valores */
			$this->addSQL(' (' . $fields . ') VALUES (' . $values . ')');
		}

		private function validarUpdate($tabla, $campos) {
			/* verificamos que se envio un nombre de tabla */
			$this->validarNombre($tabla);
			/* verificamos los campos */
			if ($campos === Null)
				/* salimos con una excepcion */
				$this->newException('No se especificaron los datos a actualizar');
			/* verificamos que los campos se especificaron en un array */
			if (gettype($campos) !== 'array')
				/* salimos con una excepcion */
				$this->newException('Los datos a actualizar deben ser especificados como Array');
			/* recorremos los datos para verificar en indice */
			foreach ($campos AS $indice => $valor) {
				/* verificamos si el indice es un string */
				if (gettype($indice) !== 'string')
					/* salimos con una excepcion */
					$this->newException('El indice de los datos a actualizar debe ser el nombre del campo');
			}
		}

		private function armarUpdate($tabla, $campos) {
			/* armamos la cadena update */
			$this->addSQL('UPDATE ' . $tabla . ' SET ', True);
			/* recorremos los campos */
			foreach ($campos AS $indice => $valor) {
				/* agregamos el campo */
				$this->addSQL($indice . ' = ' . (
					/* verificamos si es un numero */
					gettype($valor) === 'integer' ?
					/* agregamos asi como esta */
					$valor : (
						/* verificamos si es Null */
						$valor === Null ?
						/* agregamos la palabra Null */
						'Null' :
						/* agregamos el valor entre comillas */
						'\'' . addslashes($valor) . '\''
					)
				) . ', ');
			}
			/* limpiamos la consulta SQL */
			$this->cleanSQL();
		}

		private function validarDeleteFrom($tabla) {
			/* verificamos que se envio un nombre de tabla */
			$this->validarNombre($tabla);
		}

		private function armarDeleteFrom($tabla) {
			/* armamos la consulta SQL */
			$this->addSQL('DELETE FROM ' . $tabla, True);
		}

		private function addSQL($string = Null, $empty = False) {
			/* verificamos si vaciamos la cadena */
			if ($empty === True)
				/* vaciamos la cadena actual */
				$this->sqlString = False;
			/* agregamos la cadena al SQL */
			$this->sqlString .= $string;
		}

		private function showSQL() {
			/* mostramos la cadena SQL actual */
			$this->show('(' . $this->blue($this->italic($this->getSqlString())) . ')..', False);
		}

		private function cleanSQL() {
			/* verificamos si el final de la cadena termina en coma y espacio */
			if (substr($this->getSqlString(), -2) === ', ')
				/* eliminamos la coma y el espacio final */
				$this->sqlString = substr($this->getSqlString(), 0, -2);
			/* eliminamos espacios dobles en la cadena sql */
			$this->sqlString = preg_replace('/\s\s+/', ' ', $this->getSqlString());
		}
	}
?>